package com.clw.classfile;

import com.clw.classfile.attribute.Attribute;
import com.clw.classfile.attribute.info.AttributeInfo;
import com.clw.classfile.constantpool.ConstantPool;

/**
 * Created by chengliwei on 2018/11/9.
 */
public class ClassFile {

    private int magicNumber; // 4字节 0xCAFEBABE
    private short minorVersion; // 2字节
    private short majorVersion; // 2字节
    private short constantPoolCount; // 计数从1开始, class文件结构中只有常量池容器计算从1开始，其他都是从0开始
    private ConstantPool constantPool;
    private short accessFlags; // 识别一些类或者接口层次的访问信息，包括：这个Class是类还是接口；是否定义为public；是否定义为abstract；如果是类是否final等
    private short thisClass; // 用于确定这个类的全限定名
    private short superClass; // 用于确定这个类的父类全限定名。除了java.lang.Object之外，所有类的父类索引都不为0
    private short interfacesCount;
    private short[] interfaces; // 用来描述这个类实现了哪些接口
    private short fieldsCount;
    private Field[] fields; // 用于描述接口或者类中声明的变量
    private short methodsCount;
    private Method[] methods; // 用于描述接口或者类中声明的方法
    private short attributesCount;
    private AttributeInfo[] attributes;

    public ClassFile(byte[] bytes) {
        BytesReader bytesReader = BytesReader.use(bytes);
        this.magicNumber = bytesReader.readInt();
        this.minorVersion = bytesReader.readShort();
        this.majorVersion = bytesReader.readShort();
        this.constantPoolCount = bytesReader.readShort();
        this.constantPool = new ConstantPool(this.constantPoolCount, bytesReader);
        this.accessFlags = bytesReader.readShort();
        this.thisClass = bytesReader.readShort();
        this.superClass = bytesReader.readShort();
        this.interfacesCount = bytesReader.readShort();
        this.interfaces = new short[this.interfacesCount];
        for (int i = 0; i < this.interfacesCount; i++) {
            this.interfaces[i] = bytesReader.readShort();
        }
        this.fieldsCount = bytesReader.readShort();
        this.fields = new Field[this.fieldsCount];
        for (int i = 0; i < this.fieldsCount; i++) {
            this.fields[i] = new Field(bytesReader, this.constantPool);
        }
        this.methodsCount = bytesReader.readShort();
        this.methods = new Method[this.methodsCount];
        for (int i = 0; i < this.methodsCount; i++) {
            this.methods[i] = new Method(bytesReader, this.constantPool);
        }
        this.attributesCount = bytesReader.readShort();
        this.attributes = new AttributeInfo[this.attributesCount];
        for (int i = 0; i < this.attributesCount; i++) {
            this.attributes[i] = Attribute.readAttribute(bytesReader, this.constantPool);
        }
    }

    public int getMagicNumber() {
        return magicNumber;
    }

    public short getMinorVersion() {
        return minorVersion;
    }

    public short getMajorVersion() {
        return majorVersion;
    }

    public short getConstantPoolCount() {
        return constantPoolCount;
    }

    public ConstantPool getConstantPool() {
        return constantPool;
    }

    public short getAccessFlags() {
        return accessFlags;
    }

    public short getThisClass() {
        return thisClass;
    }

    public short getSuperClass() {
        return superClass;
    }

    public short getInterfacesCount() {
        return interfacesCount;
    }

    public short[] getInterfaces() {
        return interfaces;
    }

    public short getFieldsCount() {
        return fieldsCount;
    }

    public Field[] getFields() {
        return fields;
    }

    public short getMethodsCount() {
        return methodsCount;
    }

    public Method[] getMethods() {
        return methods;
    }

    public short getAttributesCount() {
        return attributesCount;
    }

    public AttributeInfo[] getAttributes() {
        return attributes;
    }
}
